package com.github.xiaolyuh.bean;

import com.github.xiaolyuh.configcenter.ConfigCenter;
import com.github.xiaolyuh.entity.RedisName;
import com.github.xiaolyuh.enums.ModelEnum;
import com.github.xiaolyuh.exception.PromotionMonitorException;
import com.github.xiaolyuh.flush.LocalCacheFlushFactory;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StopWatch;

import javax.annotation.PostConstruct;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class LocalCacheFlushBean implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(LocalCacheFlushBean.class);

    private static ScheduledThreadPoolExecutor executor = null;

    @Autowired
    private LocalCacheFlushFactory localCacheFlushFactory;

    @PostConstruct
    public void init() {
        if (executor == null) {
            executor = new ScheduledThreadPoolExecutor(Math.min(2, Runtime.getRuntime().availableProcessors()),
                    new ThreadFactoryBuilder().setNameFormat("clear-localcache-pool-%d").build());
            //钩子线程，关闭线程池
            Runtime.getRuntime().addShutdownHook(new Thread(() -> executor.shutdown()));
        }
    }

    @Override
    public void afterPropertiesSet() {
        executor.scheduleAtFixedRate(() -> flushLocalCache(), 0L, 5L, TimeUnit.SECONDS);
    }

    private void flushLocalCache() {
        StopWatch watch = new StopWatch();
        watch.start();
        try {
            //定时清除需要更新的本地缓存
            for (String site : ConfigCenter.getSiteCodes()) {
                for (ModelEnum model : ModelEnum.values()) {
                    localCacheFlushFactory.getFactory(model).flush(new RedisName(site, model));
                }
            }
        } catch (Exception e) {
            logger.error("[flush local cache]flush key occur error", PromotionMonitorException.of(e));
        } finally {
            watch.stop();
            Double second = watch.getTotalTimeSeconds();
            if (second > 10L) {
                logger.warn("[flush local cache]flush key timeout cost = {}sec", second);
            }
        }
    }

}
